import {AudioClip, resources} from 'cc';
import {AudioInfo} from "db://assets/scripts/common/AudioInfo";
import {StorageKey} from "db://assets/scripts/common/StorageKey";
import {StorageManager} from "db://assets/scripts/common/StorageManager";
import {AudioPaths} from "db://assets/scripts/common/AudioPaths";

/**
 * 音频管理器
 */
export class AudioManager {
    /**
     * 音频列表
     * 音频包括音乐和音效，这里面存的都是长时间播放的，比如循环播放的音频
     */
    private audios: Map<string, AudioInfo> = new Map<string, AudioInfo>();
    /**
     * 音乐音量
     */
    private musicVolume: number = 0.8;
    /**
     * 音效音量
     */
    private soundVolume: number = 1;

    /**
     * 音频管理器实例
     */
    private static INSTANCE: AudioManager;

    /**
     * 获取音频管理器实例
     */
    public static getInstance(): AudioManager {
        // 当实例不为空时
        if (this.INSTANCE) {
            // 直接返回
            return this.INSTANCE;
        }
        // 创建新实例
        this.INSTANCE = new AudioManager();
        // 返回音频管理器实例
        return this.INSTANCE;
    }

    private constructor() {
        // 初始化
        this.init();
    }

    /**
     * 初始化
     */
    private init() {
        // 如果开启音乐，则将音乐音量调整至0.5
        this.musicVolume = this.getMusicEnable() ? 0.5 : 0;
        // 如果开启音效，则将音效音量调整至1
        this.soundVolume = this.getSoundEnable() ? 1 : 0;

        // 缓存所有音乐

        // 缓存所有音效
        this.initSound();
    }

    /**
     * 缓存所有音效
     */
    private initSound() {
        resources.loadDir("audio/sound", AudioClip, (err, clips) => {
            if (err) {
                console.log(err)
                return;
            }

            clips.forEach(clip => {
                this.audios.set(AudioPaths.getSound(clip.name), {clip: clip, loop: false, isMusic: false});
            });
        });
    }

    /**
     * 获取音乐配置数据
     */
    public getMusicEnable(): boolean {
        let value = StorageManager.getInstance().getData(StorageKey.MUSIC);
        if (value) {
            return value === String(true);
        }
        return true;
    }

    /**
     * 获取音效配置数据
     */
    public getSoundEnable(): boolean {
        let value = StorageManager.getInstance().getData(StorageKey.SOUND);
        if (value) {
            return value === String(true);
        }
        return true;
    }

    /**
     * 播放音乐
     * 所有音乐都放在 audio/music 目录下
     * 注意：
     * 1.微信特殊处理，除一开场的音乐，其余的放在子包里头
     *
     * @param path 音乐完整路径，可以在 AudioPaths 获取
     * @param loop 是否循环播放
     */
    public playMusic(path: string, loop: boolean = false) {
        // 已缓存
        if (this.audios.has(path)) {
            this.playClip(this.audios.get(path));
            return;
        }

        // 未缓存，加载音乐
        resources.load(path, AudioClip, (err: Error, clip: AudioClip) => {
            if (err) {
                console.log(err);
                return;
            }

            // 创建音频信息
            let audioInfo: AudioInfo = {clip: clip, loop: loop, isMusic: true};
            // 当需要循环播放时
            if (loop) {
                // 缓存音频
                this.audios.set(path, audioInfo);
            }
            // 播放音频
            this.playClip(audioInfo);
        });
    }

    /**
     * 播放音效
     * 所有音效都放在 audio/sound 目录下
     *
     * @param path 音效完整路径，可以在 AudioPaths 获取
     * @param loop 是否循环播放
     */
    public playSound(path: string, loop: boolean = false) {
        // 已缓存
        if (this.audios.has(path)) {
            this.playClip(this.audios.get(path));
            return;
        }

        // 未缓存，加载音效
        resources.load(path, AudioClip, (err: Error, clip: AudioClip) => {
            if (err) {
                console.log(err);
                return;
            }

            // 创建音频信息
            let audioInfo: AudioInfo = {clip: clip, loop: loop, isMusic: false};
            // 当需要循环播放时
            if (loop) {
                // 缓存音频
                this.audios.set(path, audioInfo);
            }
            // 播放音频
            this.playClip(audioInfo);
        });
    }

    /**
     * 播放音频
     *
     * @param audioInfo 音频信息
     */
    private playClip(audioInfo: AudioInfo) {
        // 音频切片
        let clip = audioInfo.clip;

        // 音量
        let volume = audioInfo.isMusic ? this.musicVolume : this.soundVolume;
        // 设置音量
        clip.setVolume(volume);
        // 设置是否需要循环播放
        clip.setLoop(audioInfo.loop);

        // 播放
        if (audioInfo.isMusic) {
            clip.play();
        } else {
            clip.playOneShot();
        }
    }

    /**
     * 暂停播放所有音频
     * 适用于：看广告
     */
    public pauseAll() {
        this.audios.forEach(audioInfo => audioInfo.clip.pause());
    }

    /**
     * 恢复播放
     */
    public resumeAll() {
        this.audios.forEach(audioInfo => audioInfo.clip.play());
    }

    /**
     * 停止播放指定名称的音频
     *
     * @param path 音频完整路径
     */
    public stop(path: string) {
        if (this.audios.has(path)) {
            this.audios.get(path).clip.stop();
        }
    }

    /**
     * 停止播放所有音频
     */
    public stopAll() {
        this.audios.forEach(audioInfo => audioInfo.clip.stop());
    }

    /**
     * 设置音乐的音量大小
     *
     * @param volume 音量
     */
    public setMusicVolume(volume: number) {
        if (volume > 1) {
            volume = 1;
        }
        if (volume < 0) {
            volume = 0;
        }
        // 遍历音频列表
        this.audios.forEach((audioInfo: AudioInfo) => {
            // 给每个音乐设置音量
            if (audioInfo.isMusic) {
                audioInfo.clip.setVolume(volume)
            }
        });
    }

    /**
     * 设置音效音量
     *
     * @param volume 音量
     */
    public setSoundVolume(volume: number) {
        if (volume > 1) {
            volume = 1;
        }
        if (volume < 0) {
            volume = 0;
        }
        this.audios.forEach(audioInfo => {
            if (!audioInfo.isMusic) {
                audioInfo.clip.setVolume(volume)
            }
        });
    }

    /**
     * 打开音乐
     */
    public openMusic() {
        this.setMusicVolume(0.8);
        StorageManager.getInstance().setData(StorageKey.MUSIC, String(true));
    }

    /**
     * 关闭音乐
     */
    public closeMusic() {
        this.setMusicVolume(0);
        StorageManager.getInstance().setData(StorageKey.MUSIC, String(false));
    }

    /**
     * 打开音效
     */
    public openSound() {
        this.setMusicVolume(1);
        StorageManager.getInstance().setData(StorageKey.SOUND, String(true));
    }

    /**
     * 关闭音效
     */
    public closeSound() {
        this.setMusicVolume(0);
        StorageManager.getInstance().setData(StorageKey.SOUND, String(false));
    }
}